package com.cashmama.market.api.application.controller.risk;

import com.alibaba.fastjson.JSONObject;
import com.cashmama.market.api.application.controller.authentication.vos.InputParams;
import com.cashmama.market.api.application.controller.authentication.vos.ParamOptions;
import com.cashmama.market.api.application.controller.risk.response.HighmarkInitResponse;
import com.cashmama.market.api.application.controller.risk.response.UserInputInfoVO;
import com.cashmama.market.api.application.enums.ParamType;
import com.cashmama.market.api.domain.enums.Stage2ResultEnum;
import com.cashmama.market.api.domain.service.ApiTradeService;
import com.cashmama.market.api.domain.service.HighMarkReportService;
import com.cashmama.market.api.domain.vo.RequestLocalInfo;
import com.cashmama.market.api.domain.vo.risk.highmark.ReportStage1Dto;
import com.cashmama.market.api.domain.vo.risk.highmark.ReportStage2Dto;
import com.cashmama.market.api.infras.config.ApolloConfigUtil;
import com.cashmama.market.api.infras.consts.RedisKeyConsts;
import com.cashmama.market.api.infras.enums.error.OrderRestErrorEnum;
import com.cashmama.market.api.infras.exception.ApplicationException;
import com.cashmama.market.api.infras.handler.ApiResponse;
import com.cashmama.market.api.infras.utils.DateUtil;
import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.common.api.Response;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.common.utils.MD5;
import com.fqgj.xjd.user.client.*;
import com.fqgj.xjd.user.client.enums.UserHighmarkStatusEnum;
import com.fqgj.xjd.user.client.enums.UserSalaryEnum;
import com.fqgj.xjd.user.client.request.UserHighmarkVo;
import com.fqgj.xjd.user.client.response.UserAuthEmail;
import com.fqgj.xjd.user.client.response.UserInfo;
import com.fqgj.xjd.user.client.response.UserKycDocumentInfo;
import com.fqgj.xjd.user.client.response.UserPanInfo;
import com.qianli.cashmama.trade.client.trade.TradeQueryService;
import com.qianli.cashmama.trade.client.trade.response.TradeInfoResponse;
import com.qianli.cashmama.trade.common.enums.TradeAuditSubStatusEnum;
import com.qianli.cashmama.trade.common.enums.TradeStatusEnum;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

/**
 * @program: market-api
 * @description
 * @author: frank
 * @create: 2020-01-10 15:22
 **/
@RestController
@RequestMapping("highmark/")
public class HighMarkController {

    private static final Logger LOGGER = LoggerFactory.getLogger(HighMarkController.class);

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private UserEmailService userEmailService;

    @Autowired
    private UserKycDocumentService userKycDocumentService;

    @Autowired
    private UserPanService userPanService;

    @Autowired
    private HighMarkReportService highMarkReportService;

    @Autowired
    private RedisClient redisClient;

    @Autowired
    private UserHighmarkService userHighmarkService;

    @Autowired
    private ApiTradeService apiTradeService;
    @Autowired
    private TradeQueryService tradeQueryService;
    @Autowired
    private ApolloConfigUtil apolloConfigUtil;
    /**
     * 提交订单
     *
     * @param jsonObject
     * @return
     */
    @RequestMapping("/order/post")
    public ApiResponse highmarkOrderSubmit(@RequestBody JSONObject jsonObject) {
        String userCode = RequestLocalInfo.getCurrentUser().getUserCode();
        String tradeNo = jsonObject.getString("tradeNo");
        if(StringUtils.isBlank(tradeNo)){
            throw new ApplicationException(OrderRestErrorEnum.TRADE_NO_NOT_EMPTY);
        }
        //mock highmark答题数据
        if(apolloConfigUtil.getHighmarkQuestionPageUserList().contains(userCode)){
            return new ApiResponse(JSONObject.parseObject(apolloConfigUtil.getHighmarkQuestionPageResult()));
        }
        //防并发
        Response<UserHighmarkVo> userHighmarkVoResponse = userHighmarkService.getUserHighmarkByUserCode(userCode);
        if (userHighmarkVoResponse == null || !userHighmarkVoResponse.isSuccess()) {
            throw new ApplicationException("Failed !");
        }
        UserHighmarkVo userHighmarkVo = userHighmarkVoResponse.getData();
        if (userHighmarkVo != null && (
                UserHighmarkStatusEnum.SUCCESS.getStatus().equals(userHighmarkVo.getStatus())
                        || UserHighmarkStatusEnum.SUCCESS_SKIP.getStatus().equals(userHighmarkVo.getStatus())
        )) {
            LOGGER.info("highmark重复提交直接返回成功,userCode:{}", userCode);
            this.callbackTrade(tradeNo);
            return new ApiResponse(new HighmarkInitResponse(2, "Good !"));
        }

        UserInfo userInfo = userInfoService.getUserInfoByUserCode(userCode).getData();
        UserAuthEmail userAuthEmail = userEmailService.getUserEmail(userCode).getData();
        List<UserKycDocumentInfo> userKycDocumentInfoList = userKycDocumentService.getByUserCode(userCode).getData();
        UserPanInfo userPanInfo = userPanService.getByUserCode(userCode).getData();

        //必填项校验
        if (com.fqgj.common.utils.CollectionUtils.isEmpty(userKycDocumentInfoList)) {
            throw new ApplicationException("KYC is empty!");
        }
        if (userPanInfo == null || StringUtils.isEmpty(userPanInfo.getCardNo())) {
            throw new ApplicationException("Pan Card is empty!");
        }
        if (userInfo.getUserWork() == null) {
            throw new ApplicationException("Employment info is empty!");
        }

        HighmarkInitResponse highmarkInitResponse = new HighmarkInitResponse();
        //前置校验
        if (!this.checkParams(userCode, userPanInfo, userKycDocumentInfoList, userInfo)) {
            highMarkReportService.mockSuccess(userCode);
            highmarkInitResponse.setTips("Good !");
            highmarkInitResponse.setStatus(2);
        } else {
            String orderId = highMarkReportService.stage1(userCode, userInfo, userAuthEmail, userKycDocumentInfoList.get(0), userPanInfo);
            Stage2ResultEnum stage2ResultEnum = highMarkReportService.stage2(orderId, null);
            if (Stage2ResultEnum.SUCCESS.equals(stage2ResultEnum)) {
                highMarkReportService.stage3(orderId);
                highmarkInitResponse.setTips("Great !");
                highmarkInitResponse.setStatus(2);
                this.callbackTrade(tradeNo);
            } else if (Stage2ResultEnum.QUESTION.equals(stage2ResultEnum)) {
                ReportStage2Dto reportStage2Dto = redisClient.get(RedisKeyConsts.HIGHMARK_STAGE2_KEY, orderId);
                highmarkInitResponse.setTips("Select !");
                highmarkInitResponse.setInputParams(getQuestion(reportStage2Dto));
                highmarkInitResponse.setStatus(3);
            } else if (Stage2ResultEnum.NO_HIT.equals(stage2ResultEnum)) {
                highMarkReportService.noHitSuccess(userCode);
                highmarkInitResponse.setTips("Good !");
                highmarkInitResponse.setStatus(2);
                this.callbackTrade(tradeNo);
            } else {
                highmarkInitResponse.setTips("Failed !");
                highmarkInitResponse.setStatus(1);
            }
        }
        return new ApiResponse(highmarkInitResponse);
    }

    /**
     * 提交问题
     *
     * @param jsonObject
     * @return
     */
    @RequestMapping("/question/post")
    public ApiResponse highmarkQuestionPost(@RequestBody JSONObject jsonObject) {

        String userCode = RequestLocalInfo.getCurrentUser().getUserCode();
        String tradeNo = jsonObject.getString("tradeNo");
        if(StringUtils.isBlank(tradeNo)){
            throw new ApplicationException(OrderRestErrorEnum.TRADE_NO_NOT_EMPTY);
        }
        //mock highmark答题数据
        if(apolloConfigUtil.getHighmarkQuestionPageUserList().contains(userCode)){
            return new ApiResponse(JSONObject.parseObject(apolloConfigUtil.getHighmarkQuestionPageResult()));
        }
        //防并发
        Response<UserHighmarkVo> userHighmarkVoResponse = userHighmarkService.getUserHighmarkByUserCode(userCode);
        if (userHighmarkVoResponse == null || !userHighmarkVoResponse.isSuccess()) {
            throw new ApplicationException("Failed !");
        }
        UserHighmarkVo userHighmarkVo = userHighmarkVoResponse.getData();
        if (userHighmarkVo != null && (
                UserHighmarkStatusEnum.SUCCESS.getStatus().equals(userHighmarkVo.getStatus())
                        || UserHighmarkStatusEnum.SUCCESS_SKIP.getStatus().equals(userHighmarkVo.getStatus())
        )) {
            LOGGER.info("highmark重复提交直接返回成功2,userCode:{}", userCode);
            this.callbackTrade(tradeNo);
            return new ApiResponse(new HighmarkInitResponse(2, "Good !"));
        }

        ReportStage1Dto reportStage1Dto = redisClient.get(RedisKeyConsts.HIGHMARK_STAGE1_USERCODE_KEY, userCode);
        if (reportStage1Dto == null) {
            throw new ApplicationException("error!");
        }
        String orderId = reportStage1Dto.getOrderId();
        ReportStage2Dto reportStage2DtoHistory = redisClient.get(RedisKeyConsts.HIGHMARK_STAGE2_KEY, orderId);
        if (reportStage2DtoHistory == null) {
            throw new ApplicationException("error!");
        }

        String key = getQuestionKey(reportStage2DtoHistory.getQuestion());
        Integer index = jsonObject.getInteger(key);//获取key对应的选项index
        if (index == null) {
            throw new ApplicationException("Question index error!");
        }
        //提交答案
        String answer = reportStage2DtoHistory.getOptionList().get(index).trim();
        Stage2ResultEnum stage2ResultEnum = highMarkReportService.stage2(orderId, answer);
        HighmarkInitResponse highmarkInitResponse = new HighmarkInitResponse();
        if (Stage2ResultEnum.SUCCESS.equals(stage2ResultEnum)) {
            highMarkReportService.stage3(orderId);
            highmarkInitResponse.setTips("Great !");
            highmarkInitResponse.setStatus(2);
            this.callbackTrade(tradeNo);
        } else if (Stage2ResultEnum.QUESTION.equals(stage2ResultEnum)) {
            ReportStage2Dto reportStage2Dto = redisClient.get(RedisKeyConsts.HIGHMARK_STAGE2_KEY, orderId);
            highmarkInitResponse.setTips("Select !");
            highmarkInitResponse.setInputParams(getQuestion(reportStage2Dto));
            highmarkInitResponse.setStatus(3);
        } else if (Stage2ResultEnum.NO_HIT.equals(stage2ResultEnum)) {
            highMarkReportService.noHitSuccess(userCode);
            highmarkInitResponse.setTips("Good !");
            highmarkInitResponse.setStatus(2);
            this.callbackTrade(tradeNo);
        } else {
            highmarkInitResponse.setTips("Failed !");
            highmarkInitResponse.setStatus(1);
        }
        return new ApiResponse(highmarkInitResponse);
    }

    /**
     * highmark获取成功后，回调交易
     */
    private void callbackTrade(String tradeNo) {
        String userCode = RequestLocalInfo.getCurrentUser().getUserCode();
        Response<TradeInfoResponse> response = tradeQueryService.queryByTradeNo(tradeNo);
        if (response.getData() != null && TradeStatusEnum.AUDIT_WATTING.equals(response.getData().getOrderStatus())
                && Objects.equals(response.getData().getAuditSubStatus(), TradeAuditSubStatusEnum.WAITING_HIGHMARK)) {
            LOGGER.info("highmark获取成功后回调交易,userCode:{},tradeNo:{}", userCode, response.getData().getTradeNo());
            apiTradeService.completeHighMark(response.getData().getTradeNo());
        }
    }

    /**
     * 前置项校验
     *
     * @param userCode
     * @param userPanInfo
     * @param userKycDocumentInfoList
     * @param userInfo
     * @return
     */
    public boolean checkParams(String userCode, UserPanInfo userPanInfo, List<UserKycDocumentInfo> userKycDocumentInfoList, UserInfo userInfo) {
        if(apolloConfigUtil.isServerTest()){
            return true;
        }
        try {
            if (StringUtils.isEmpty(userInfo.getUserBase().getBirthday())) {
                throw new ApplicationException("Birthday is empty!");
            }
            if (this.getCurrentAge(DateUtil.getDate(userInfo.getUserBase().getBirthday(), "yyyy-MM-dd")) < 20) {
                throw new ApplicationException("Age is not enough");
            }
            if (UserSalaryEnum.UNDER_5000.getType().equals(userInfo.getUserWork().getSalary())
                    || UserSalaryEnum.BETWEEN_5000_AND_9999.getType().equals(userInfo.getUserWork().getSalary())) {
                throw new ApplicationException("Low income");
            }
            return true;
        } catch (ApplicationException e) {
            LOGGER.info("用户基础信息校验失败,userCode:{}", userCode, e);
            return false;
        }
    }

    /**
     * 根据生日计算当前周岁数
     */
    public int getCurrentAge(Date birthday) {
        // 当前时间
        Calendar curr = Calendar.getInstance();
        // 生日
        Calendar born = Calendar.getInstance();
        born.setTime(birthday);
        // 年龄 = 当前年 - 出生年
        int age = curr.get(Calendar.YEAR) - born.get(Calendar.YEAR);
        if (age <= 0) {
            return 0;
        }
        // 如果当前月份小于出生月份: age-1
        // 如果当前月份等于出生月份, 且当前日小于出生日: age-1
        int currMonth = curr.get(Calendar.MONTH);
        int currDay = curr.get(Calendar.DAY_OF_MONTH);
        int bornMonth = born.get(Calendar.MONTH);
        int bornDay = born.get(Calendar.DAY_OF_MONTH);
        if ((currMonth < bornMonth) || (currMonth == bornMonth && currDay <= bornDay)) {
            age--;
        }
        return age < 0 ? 0 : age;
    }

    /**
     * 组装问题
     *
     * @param reportStage2Dto
     * @return
     */
    private List<UserInputInfoVO> getQuestion(ReportStage2Dto reportStage2Dto) {
        List<UserInputInfoVO> userInputInfoList = new ArrayList<>();
        List<InputParams> inputParamList = new ArrayList<>();
        InputParams relationParam = new InputParams();
        relationParam.setInputValue("");
        relationParam.setParamOptions(convert2ParamOption(reportStage2Dto.getOptionList()));
        relationParam.setBurialPointName(null);
        relationParam.setParamName(reportStage2Dto.getQuestion());
        relationParam.setParam(getQuestionKey(reportStage2Dto.getQuestion()));
        relationParam.setParamType(ParamType.SINGLE_SELECT.getType());
        relationParam.setInputDesc("Please choose");
        inputParamList.add(relationParam);

        UserInputInfoVO userInputInfoVO = new UserInputInfoVO();
        userInputInfoVO.setButtonText("Submit");
        userInputInfoVO.setInputParams(inputParamList);
        userInputInfoList.add(userInputInfoVO);
        return userInputInfoList;
    }

    /**
     * 直系亲属转换为option
     *
     * @param relationOptions
     * @return
     */
    private List<ParamOptions> convert2ParamOption(List<String> relationOptions) {
        List<ParamOptions> paramOptionsList = new ArrayList<>();
        if (CollectionUtils.isEmpty(relationOptions)) {
            return new ArrayList<>();
        }
        for (int i = 0; i < relationOptions.size(); i++) {
            ParamOptions paramOption = new ParamOptions();
            paramOption.setOptionId(i);
            paramOption.setOptionValue(relationOptions.get(i));
            paramOptionsList.add(paramOption);
        }
        return paramOptionsList;
    }

    /**
     * get key
     *
     * @param question
     * @return
     */
    private String getQuestionKey(String question) {
        String tmp = MD5.md5(question);
        return "key" + tmp.substring(tmp.length() - 6);
    }
}
